use axum::{
    body::Body,
    http::StatusCode,
    response::{IntoResponse, Response},
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

// 状态码
pub const CODE_SUCCESS: StatusCode = StatusCode::OK;
pub const CODE_ERROR: StatusCode = StatusCode::INTERNAL_SERVER_ERROR;

/**
 * @desc 自定义response
 */
#[derive(Debug, Deserialize, Serialize)]
pub struct RespVO<T> {
    code: u16,
    msg: String,
    data: Option<T>,
}

impl<T: DeserializeOwned + Serialize> RespVO<T> {
    pub fn from_result(code: Option<u16>, msg: Option<String>, data: Option<T>) -> Self {
        Self {
            code: code.unwrap_or(CODE_SUCCESS.as_u16()),
            msg: msg.unwrap_or_else(|| "success".to_string()),
            data,
        }
    }

    pub fn success(msg: String, data_opt: Option<T>) -> Self {
        Self::from_result(Some(CODE_SUCCESS.as_u16()), Some(msg), data_opt)
    }

    pub fn success_without_data(msg: String) -> Self {
        Self::success(msg, None)
    }

    pub fn from_error(code: Option<u16>, msg: String, data: Option<T>) -> Self {
        Self {
            code: code.unwrap_or(CODE_ERROR.as_u16()),
            msg,
            data,
        }
    }

    pub fn error(msg: String, data_opt: Option<T>) -> Self {
        Self::from_error(Some(CODE_ERROR.as_u16()), msg, data_opt)
    }

    pub fn error_without_data(msg: String) -> Self {
        Self::error(msg, None)
    }
}

impl<T> IntoResponse for RespVO<T>
where
    T: Serialize + DeserializeOwned,
{
    fn into_response(self) -> Response<Body> {
        let body = match serde_json::to_string(&self) {
            Ok(json) => Body::from(json),
            Err(_) => Body::from("{\"code\":500,\"msg\":\"Internal Server Error\",\"data\":null}"),
        };

        Response::builder()
            .header("Cache-Control", "no-cache")
            .header("Content-Type", "application/json;charset=UTF-8")
            .body(body)
            .unwrap()
    }
}
